/**
 * 项目名：化工企业安全生产信息化管理平台
 * 日期：    2020-03-17 14:00:30
 * Copyright (c) 2015- -版权所有
 */

package com.joysuch.wwyt.edu.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.google.common.collect.Lists;
import com.joysuch.wwyt.bp.repository.BpDepartDao;
import com.joysuch.wwyt.core.bean.SimpleSelectListBean;
import com.joysuch.wwyt.core.common.ajax.ResultBean;
import com.joysuch.wwyt.core.common.util.DateTimeUtil;
import com.joysuch.wwyt.core.common.util.PageDataUtils;
import com.joysuch.wwyt.core.common.util.PageDataUtils.PageDataConvert;
import com.joysuch.wwyt.core.exception.BusinessRestrictionsException;
import com.joysuch.wwyt.core.repository.BaseTypeGroupItemDao;
import com.joysuch.wwyt.core.repository.BaseUserDao;
import com.joysuch.wwyt.core.service.BizCodeGeneratorFacade;
import com.joysuch.wwyt.edu.bean.*;
import com.joysuch.wwyt.edu.bean.EduCertificateListBean.SearchEduCertificate;
import com.joysuch.wwyt.edu.entity.EduCertificate;
import com.joysuch.wwyt.edu.entity.EduCertificateUser;
import com.joysuch.wwyt.edu.entity.dsl.QEduCertificate;
import com.joysuch.wwyt.edu.enums.CertificateRemindTypes;
import com.joysuch.wwyt.edu.enums.CertificateTypes;
import com.joysuch.wwyt.edu.mapper.WwytEduCertificateUserMapper;
import com.joysuch.wwyt.edu.repository.EduCertificateDao;
import com.joysuch.wwyt.edu.repository.EduCertificateUserDao;
import com.joysuch.wwyt.edu.service.EduCertificateService;
import com.joysuch.wwyt.edu.service.EduCertificateUserService;
import com.querydsl.core.types.ExpressionUtils;
import com.querydsl.core.types.Predicate;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import javax.transaction.Transactional;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Service
@Transactional
public class EduCertificateServiceImpl implements EduCertificateService {

    @Autowired
    private EduCertificateDao dao;
    @Autowired
    private BizCodeGeneratorFacade bizCodeGeneratorFacade;
    @Autowired
    private EduCertificateUserDao eduCertificateUserDao;
    @Autowired
    private BaseUserDao baseUserDao;
    @Autowired
    private BpDepartDao bpDepartDao;
    @Autowired
    private EduCertificateUserService eduCertificateUserService;
    @Autowired
    private BaseTypeGroupItemDao baseTypeGroupItemDao;
    @Autowired
    private WwytEduCertificateUserMapper eduCertificateUserMapper;


    @Override
    public EduCertificate add(EduCertificateEditBean entity) {
        judgeData(entity);
        if (CertificateTypes.LIMITED_MONTHS.is(entity.getEffectiveType())) {
            Assert.notNull(entity.getEffectiveDurationMonth(), "选择定期时，证书有效期不能为空");
            Assert.isTrue(entity.getEffectiveDurationMonth() > 0, "选择定期时，证书有效期必须大于0");
        }
        Assert.isTrue(dao.countOfName(entity.getName()) == 0, String.format("证书[%s]已经存在", entity.getName()));
        EduCertificate content = new EduCertificate();
        if (StringUtils.isNotBlank(entity.getCode())) {
            Assert.isTrue(dao.countOfCode(entity.getCode()) == 0, String.format("编号%s已经存在", entity.getCode()));
            content.setCode(entity.getCode());
        } else {
            content.setCode(bizCodeGeneratorFacade.zhengShu());
        }
        BeanUtils.copyProperties(entity, content, "id", "code");
        //提醒人
        List<Long> remindUserIds = entity.getRemindUserIds();
        if (remindUserIds != null) {
            content.setRemindUserIdsJson(JSON.toJSONString(remindUserIds));
        }
        content.setState((byte) 0);
        return dao.save(content);
    }

    @Override
    public void update(EduCertificateEditBean entity) {
        judgeData(entity);
        if (CertificateTypes.LIMITED_MONTHS.is(entity.getEffectiveType())) {
            Assert.notNull(entity.getEffectiveDurationMonth(), "选择定期时，证书有效期不能为空");
            Assert.isTrue(entity.getEffectiveDurationMonth() > 0, "选择定期时，证书有效期必须大于0");
        } else {
            entity.setEffectiveDurationMonth(null);
        }
        Assert.isTrue(dao.countOfNameExcludeId(entity.getName(), entity.getId()) == 0,
                String.format("证书[%s]已经存在", entity.getName()));
        EduCertificate content = dao.findById(entity.getId()).get();
        Integer turnLimited = turnLimited(entity.getEffectiveType(), content.getEffectiveType());
        boolean monthChange = monthChange(entity.getEffectiveDurationMonth(), content.getEffectiveDurationMonth());
        BeanUtils.copyProperties(entity, content, "id", "code");
        //提醒人
        List<Long> remindUserIds = entity.getRemindUserIds();
        if (remindUserIds != null) {
            content.setRemindUserIdsJson(JSON.toJSONString(remindUserIds));
        } else {
            content.setRemindUserIdsJson(JSON.toJSONString(Lists.newArrayList()));
        }
        content.setDepartId(entity.getDepartId());
        EduCertificate save = dao.save(content);
        Integer month = save.getEffectiveDurationMonth();
        Long certId = save.getId();

        //证书的修改需要更新相应人员的证书过期信息
        //不做消息通知
        List<EduCertificateUser> certificateUserList = eduCertificateUserDao.findByCertId(certId);
        if (CollectionUtils.isEmpty(certificateUserList)) {
            return;
        }
        if (turnLimited == 0) {
            if (monthChange) {
                certOutOfTimeUpdate(month, certificateUserList);
            }
        }
        //长期有效->定期有效
        else if (turnLimited == 1) {
            certOutOfTimeUpdate(month, certificateUserList);
        }
        //定期有效->长期有效
        else if (turnLimited == 2) {
            for (EduCertificateUser certificateUser : certificateUserList) {
                certificateUser.setOutOfDateTime(null);
            }
        }
        for (EduCertificateUser certificateUser : certificateUserList) {
            eduCertificateUserService.setCertStatus(certificateUser);
        }
        eduCertificateUserDao.saveAll(certificateUserList);
    }

    /**
     * 人员证书过期时间修改
     */
    private void certOutOfTimeUpdate(Integer month, List<EduCertificateUser> certificateUserList) {
        for (EduCertificateUser certificateUser : certificateUserList) {
            Date takenTime = certificateUser.getTakenTime();
            LocalDate localDate = DateTimeUtil.date2LocalDateTime(takenTime).toLocalDate().plusMonths(month);
            LocalDateTime outOfDateTime = LocalDateTime.of(localDate, LocalTime.of(0, 0, 0));
            certificateUser.setOutOfDateTime(DateTimeUtil.localDateTime2Date(outOfDateTime));
        }
    }

    /**
     * 证书有效期非空情况下数量是否改变
     */
    private boolean monthChange(Integer newMonth, Integer oldMonth) {
        if (newMonth == null || oldMonth == null) {
            return false;
        }
        return !newMonth.equals(oldMonth);
    }

    /**
     * 证书有效期类型
     * 0 没变
     * 1 长期有效->定期有效
     * 2 定期有效->长期有效
     */
    private Integer turnLimited(Byte newType, Byte oldType) {
        if (newType.equals(oldType)) {
            return 0;
        }
        if (CertificateTypes.LONG_TERM.is(oldType) && CertificateTypes.LIMITED_MONTHS.is(newType)) {
            return 1;
        }
        return 2;
    }

    private void judgeData(EduCertificateEditBean entity) {
        entity.setName(entity.getName().trim());
        Integer effectiveDurationMonth = entity.getEffectiveDurationMonth();
        if (entity.getExpireRemindOrNot() == 1) {
            String remindType = entity.getRemindType();
            if (StringUtils.isEmpty(remindType) || entity.getRemindTime() == null ||
                    (CollectionUtils.isEmpty(entity.getRemindUserIds()) && entity.getDepartId() == null)) {
                throw new IllegalArgumentException("到期提醒选择是，到期类型/提醒时间/提醒人不能为空");
            }
            if (!CollectionUtils.isEmpty(entity.getRemindUserIds()) && entity.getDepartId() != null) {
                throw new IllegalArgumentException("提醒人，人员和部门二选一");
            }
            Integer hours = CertificateRemindTypes.getHours(remindType);
            Assert.notNull(hours, "不支持此到期类型");
            //判断时间
            if (effectiveDurationMonth != null && effectiveDurationMonth * 30 * 24 <= hours) {
                throw new IllegalArgumentException("到期提醒时间需短于有效期");
            }
        }
    }

    @Override
    public Page<EduCertificateListBean> findByPage(Pageable page, SearchEduCertificate condition) {
        Predicate predicate = prepareListSearchCondition(condition);

        Page<EduCertificate> data = predicate == null ? dao.findAll(page) : dao.findAll(predicate, page);

        return PageDataUtils.convertPageData(data, new PageDataConvert<EduCertificateListBean, EduCertificate>() {

            @Override
            public EduCertificateListBean convert(EduCertificate f) {
                EduCertificateListBean bean = new EduCertificateListBean();
                BeanUtils.copyProperties(f, bean);
                return bean;
            }

        });
    }

    private Predicate prepareListSearchCondition(SearchEduCertificate condition) {
        Predicate p = null;
        QEduCertificate q = QEduCertificate.eduCertificate;
        if (condition.getName() != null) {
            p = ExpressionUtils.and(p, q.name.contains(condition.getName()));
        }
        if (condition.getCode() != null) {
            p = ExpressionUtils.and(p, q.code.contains(condition.getCode()));
        }
        return p;
    }

    @Override
    public void delete(Long id) throws BusinessRestrictionsException {
        // 校验业务逻辑是否允许删除。如本数据被其他业务关联，删除后导致其他业务不可用。不能删除时将抛出业务异常
        checkBussinessRestrictions(id);
        dao.deleteById(id);
    }

    /**
     * 校验业务逻辑是否允许删除。如本数据被其他业务关联，删除后导致其他业务不可用
     *
     * @param id 要删除的业务ID
     */
    private void checkBussinessRestrictions(Long id) throws BusinessRestrictionsException {
        Assert.isTrue(eduCertificateUserDao.queryUserCountOfCertificate(id) == 0, "证书已颁发给用户，不能删除");
    }

    @Override
    public EduCertificate findById(Long id) {
        return dao.findById(id).orElse(null);
    }

    /**
     * 获取证书列表
     *
     * @return
     */
    @Override
    public List<SimpleSelectListBean> getSimpleList(Integer useState) {
        List<EduCertificate> eduList = new ArrayList<>();
        if (useState != null) {
            eduList = dao.getSimpleListByUseState(useState);
        } else {
            eduList = dao.getSimpleList();
        }
        List<SimpleSelectListBean> list = new ArrayList<>();
        for (EduCertificate eduCertificate : eduList) {
            SimpleSelectListBean bean = new SimpleSelectListBean();
            bean.setValue(eduCertificate.getId());
            bean.setLabel(eduCertificate.getName());
            list.add(bean);
        }
        return list;
    }

    /**
     * 获取人员所在证书
     *
     * @param pageable
     * @param param
     * @return
     */
    @Override
    public ResultBean getSimplePage(Pageable pageable, EduCertPageParam param) {
        com.baomidou.mybatisplus.extension.plugins.pagination.Page<EduCertListDto> page = new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>(pageable.getPageNumber() + 1, pageable.getPageSize());
        IPage<EduCertListDto> eduCertList;
        if (param.getUserContractorFlag() != null && param.getUserContractorFlag().equals(0)) {
            eduCertList = eduCertificateUserMapper.getCertsList(page, param.getUserId(), param.getUserContractorFlag(), param.getUseState(), param.getCertificateStatus(), param.getCertId(),param.getUserNameOrCertNo(),param.getUserNameOrUserCode(),param.getCertNo());
        } else if (param.getUserContractorFlag() != null && param.getUserContractorFlag().equals(1)) {
            eduCertList = eduCertificateUserMapper.getContractStaffCertsList(page, param.getUserId(), param.getUserContractorFlag(), param.getUseState(), param.getCertificateStatus(), param.getCertId(),param.getUserNameOrCertNo(),param.getUserNameOrUserCode(),param.getCertNo());
        } else {
            eduCertList = eduCertificateUserMapper.getCertsListByUseStateAndCertificateStatus(page, param.getUseState(), param.getCertificateStatus(), param.getCertId(),param.getUserNameOrCertNo(),param.getUserNameOrUserCode(),param.getCertNo());
        }
        return ResultBean.pageData(eduCertList.getRecords(), eduCertList.getTotal());
    }

    @Override
    public EduCertificateEditBean getById(Long id) {
        EduCertificate entity = findById(id);
        if (entity == null) {
            return null;
        }
        EduCertificateEditBean bean = new EduCertificateEditBean();
        BeanUtils.copyProperties(entity, bean);
        String remindUserIdsJson = entity.getRemindUserIdsJson();
        if (remindUserIdsJson != null) {
            List<Long> longs = JSON.parseArray(remindUserIdsJson, Long.class);
            List<EduCertEditUserNameBean> eduCertEditUserNameBeans = Lists.newArrayList();
            for (Long aLong : longs) {
                String name = baseUserDao.getRealNameById(aLong);
                EduCertEditUserNameBean eduCertEditUserNameBean = new EduCertEditUserNameBean(aLong, name);
                eduCertEditUserNameBeans.add(eduCertEditUserNameBean);
            }
            bean.setRemindUserIds(longs);
            bean.setUserNames(eduCertEditUserNameBeans);
        }
        if (entity.getDepartId() == null) {
            bean.setUserDepartFlag(0);
        } else {
            bean.setUserDepartFlag(1);
            Long departId = entity.getDepartId();
            String departName = bpDepartDao.getNameById(departId);
            bean.setDepartName(new EduCertEditUserNameBean(departId, departName));
        }
        //证书类型
        Long certTypeId = bean.getCertTypeId();
        bean.setCertTypeName(certTypeId == null ? null : baseTypeGroupItemDao.findNameById(certTypeId));
        return bean;
    }

}
